package server

import (
	"encoding/json"
	"errors"
	"sync"
	"time"

	"github.com/google/uuid"
	"github.com/gorilla/websocket"
)

// Client 表示一个WebSocket客户端连接
type Client struct {
	id      string
	conn    *websocket.Conn
	closed  bool
	closeMu sync.RWMutex
	// 添加消息通道
	send chan NetData
	// 添加完成通道，用于优雅关闭
	done chan struct{}
}

// NewClient 创建一个新的客户端实例
func NewClient(conn *websocket.Conn) *Client {
	client := &Client{
		id:   uuid.New().String(),
		conn: conn,
		send: make(chan NetData, 256), // 缓冲通道，避免阻塞
		done: make(chan struct{}),
	}

	// 启动写入 goroutine
	go client.writePump()

	return client
}

// writePump 在单独的 goroutine 中处理所有写入操作
func (c *Client) writePump() {
	ticker := time.NewTicker(pingPeriod)
	defer func() {
		ticker.Stop()
		c.conn.Close()
	}()

	for {
		select {
		case data, ok := <-c.send:
			c.conn.SetWriteDeadline(time.Now().Add(writeWait))
			if !ok {
				// 通道已关闭，发送关闭消息
				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
				return
			}

			// 写入 JSON 消息
			if err := c.conn.WriteJSON(data); err != nil {
				return
			}
		case <-ticker.C:
			// 发送 ping 消息保持连接活跃
			c.conn.SetWriteDeadline(time.Now().Add(writeWait))
			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
				return
			}
		case <-c.done:
			return
		}
	}
}

// ID 返回客户端ID
func (c *Client) ID() string {
	return c.id
}

// RemoteAddr 返回客户端远程地址
func (c *Client) RemoteAddr() string {
	return c.conn.RemoteAddr().String()
}

// Send 发送数据到客户端
func (c *Client) Send(data NetData) error {
	c.closeMu.RLock()
	if c.closed {
		c.closeMu.RUnlock()
		return errors.New("connection closed")
	}
	c.closeMu.RUnlock()

	select {
	case c.send <- data:
		return nil
	default:
		// 如果通道已满，关闭连接
		c.Close()
		return errors.New("client send buffer is full")
	}
}

// Receive 从客户端接收数据
func (c *Client) Receive() (NetData, error) {
	var data NetData

	c.closeMu.RLock()
	if c.closed {
		c.closeMu.RUnlock()
		return data, errors.New("connection closed")
	}
	c.closeMu.RUnlock()

	// 设置读取超时
	c.conn.SetReadDeadline(time.Now().Add(pongWait))

	// 设置Pong处理器
	c.conn.SetPongHandler(func(string) error {
		c.conn.SetReadDeadline(time.Now().Add(pongWait))
		return nil
	})

	// 读取WebSocket消息
	messageType, message, err := c.conn.ReadMessage()
	if err != nil {
		return data, err
	}

	// 只处理文本消息
	if messageType != websocket.TextMessage {
		return data, errors.New("unsupported message type")
	}

	// 解析JSON数据
	if err := json.Unmarshal(message, &data); err != nil {
		return data, err
	}

	return data, nil
}

// Close 关闭客户端连接
func (c *Client) Close() error {
	c.closeMu.Lock()
	defer c.closeMu.Unlock()

	if c.closed {
		return nil
	}

	c.closed = true

	// 关闭 done 通道，通知 writePump goroutine 退出
	close(c.done)

	// 关闭 send 通道
	close(c.send)

	return c.conn.Close()
}

// IsClosed 检查客户端连接是否已关闭
func (c *Client) IsClosed() bool {
	c.closeMu.RLock()
	defer c.closeMu.RUnlock()
	return c.closed
}

// WebSocket超时常量
const (
	// 写入超时时间
	writeWait = 10 * time.Second

	// Pong等待时间
	pongWait = 10 * time.Second

	// Ping周期，必须小于pongWait
	pingPeriod = (pongWait * 5) / 10
)
